#ifndef _RING_QUEUE_  // 如果没有定义宏_RING_QUEUE_就执行下面步骤
#define _RING_QUEUE_

// 防止头文件重复定义,和微软#pragma once同理
#include <iostream>
#include <vector>
#include "Mutex.hpp"
#include "Sem.hpp"

static const int defaultCapacity = 6;  // 默认给6个空间

template<class T>
class RingQueue
{
public:
    RingQueue(int capacity = defaultCapacity)
    :_rq(capacity), _capacity(capacity)
    ,_PSem(capacity), _CSem(0)
    ,_pindex(0), _cindex(0)
    {}

    // 生产者
    void push(const T& val)
    {
        _PSem.p();  // 剩余空间数量--
        MutexGuardian mtx(_mtx);  // 上锁 生产者生产者之间保持互斥
        _rq[_pindex++] = val;
        _pindex %= _capacity;  // 环形队列
        _CSem.v();  // 资源空间++
    }

    // 消费者
    void pop(T* val)
    {
        _CSem.p();  // 资源空间--
        MutexGuardian mtx(_mtx);
        *val = _rq[_cindex++];
        _cindex %= _capacity;
        _PSem.v();  // 剩余空间++
    }

    void debug()
    {
        // 测试函数

    }
private:
    std::vector<T> _rq;
    size_t _capacity;
    SemObject _PSem;  // 生产者信号量，初始化为申请空间个数，为剩余空间个数
    SemObject _CSem;  // 消费者信号量，初始化为0个，为生产者生产还未消费的资源个数
    Mutex _mtx;       // 互斥锁对象
    int _pindex;      // 生产者下标
    int _cindex;      // 消费者下标
};

#endif  // 预处理结束